home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-08-15 | 16.3 KB | 430 lines | [TEXT/MPS ] |
- // Copyright © 1990 Apple Computer, Inc. All rights reserved.
- #ifndef __IACHeaders__ // Every source file which uses the headers defined
- #include "IACHeaders.h" // In the main header file get the file included.
- #endif
-
- extern char *tseStrCpy(char *s,char *t);
-
- /**********************************Comment*****************************************
- * TDriver::TDriver is the constructor. It simply zeros the strings, and message
- * arrays.
- **********************************End Comment************************************/
- TDriver::TDriver()
- {
- short i, k;
- char zeroChar = kZeroChar;
-
- for (i = 0; i < kMaxApps; i++)
- for (k = 0; k < 255; k++)
- fAppNameArray[i][k] = kZeroChar;
- for (i = 0; i < kMaxMessages; i++)
- fMessageArray[i] = nil;
- }
-
- /**********************************Comment*****************************************
- * TDriver::~TDriver is the destructor. It's just a place holder for the time being.
- **********************************End Comment************************************/
- TDriver::~TDriver()
- {
- }
-
-
- /**********************************Comment*****************************************
- * TDriver::iacOpen would do any setup we needed to do when the driver was opened.
- * The constructor handles most of this for us. You can put anything you like in
- * here, but I just return noErr.
- **********************************End Comment************************************/
- OSErr
- TDriver::iacOpen(ParmBlkPtr oParmBlock)
- {
- #ifdef DEBUG
- DebugStr("\pIn Open now.");
- #endif
-
- return (oParmBlock->ioParam.ioResult = noErr);
- }
-
-
- /**********************************Comment*****************************************
- * TDriver::iacPrime just returns an error explaining the two calls are not implemented
- * I could have used the flags in the DCE flags word to let the Device Manager handle
- * this notification to the caller. But, again, I wanted to show how the routine
- * would be set up, and how to test the ioTrap word for the proper thing.
- **********************************End Comment************************************/
- OSErr
- TDriver::iacPrime(ParmBlkPtr pParmBlock)
- {
- #ifdef DEBUG
- DebugStr("\pIn Prime now.");
- #endif
- switch (pParmBlock->ioParam.ioTrap & 0x00FF)
- {
- case kRdCmd :
- return (pParmBlock->ioParam.ioResult = kNoRead);
- case kWrCmd :
- return (pParmBlock->ioParam.ioResult = kNoWrite);
- default :
- break;
- }; // switch statement.
- return(kNoErr);
- } // TDriver::iacPrime
-
-
- /**********************************Comment*****************************************
- * TDriver::iacControl does most of the work for us. This is where we send and
- * receive messages. It's also where we register and unregister applications with
- * our driver. We also have to handle KillIO calls because the chapter tells us to.
- * The tricky part is KillIO has to return via an RTS, so we'll signal the assembly
- * to RTS by putting a 1 in the return parameter.
- *
- * A special note about Virtual Memory here. I chose to implement the send/receive
- * messages functionality here because I needed more information than just the
- * actual message being passed -- I needed to know who it was from and who it was to.
- * This will cause a problem with VM if these Control calls are used at interrupt
- * time. Virtual memory watches the _Read and _Write traps and makes sure the memory
- * addressed by ioBuffer stays in physical memory, but it neglects to do the same
- * for csParam. Hence, the IACRecord structure (and pointers within that structure)
- * may or MAY NOT be in physical RAM at the time of the call. If this happens at
- * interrupt time and a page fault occurs, we're completely hosed.
- * Now, to work around this in the future, I'd have to use the _Read and _Write traps
- * and format my ioBuffer to contain the information in IACRecord -- it'd have to
- * pass ALL the information (with NO pointers to other information), so that's a bit
- * of a chore. It's a particularly unpleasant aspect about VM, which could cause a
- * few device drivers to fail big-time.
- *
- * Note the particularly ugly type-cast of the csParam address. We have to do this
- * so we can get a pointer (long) to the actual IACRecord structure. You'll have to
- * do the same kind of thing when calling this routine. Anyway, just to explain --
- * I take the address of the csParam structure, make it a pointer to a long, and then
- * dereference it. Finally, I type-cast it to a pointer to an IACRecord structure.
- * If you're in to experimenting, you might try doing different things to get at what
- * you THINK is the right address, and then dumpobj the result to see what the
- * compiler did. (that's what I had to do when I didn't understand why it was using
- * PEAs instead of MOVE.Ls.
- **********************************End Comment************************************/
- OSErr
- TDriver::iacControl(ParmBlkPtr cntlParmBlock)
- {
- #ifdef DEBUG
- DebugStr("\pIn Control now.");
- #endif
- switch (cntlParmBlock->cntrlParam.csCode)
- {
- case kKillIO:
- return (cntlParmBlock->cntrlParam.ioResult = kAbnormErr);
- case kGoodbye:
- return(cntlParmBlock->cntrlParam.ioResult = noErr);
- case kRegisterApp:
- return (cntlParmBlock->cntrlParam.ioResult = this->RegisterApp( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
- case kSendMessage :
- return (cntlParmBlock->cntrlParam.ioResult = this->SendMessage( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
- case kReceiveMessage :
- return (cntlParmBlock->cntrlParam.ioResult = this->ReceiveMessage( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
- case kUnregisterApp :
- return (cntlParmBlock->cntrlParam.ioResult = this->UnregisterApp( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
- default :
- return (kBadCsCode);
- }; // switch statement
- return(kNoErr); // The linker warns about "no return values" if I don't put this in.
- } // TDriver::iacControl
-
-
-
- /**********************************Comment*****************************************
- * TDriver::iacStatus returns a couple of status-like pieces of information. It calls
- * the AnyMessagesForMe routine to see if there are any messages addressed to the
- * calling application. It also calls WhosThere so a calling application can determine
- * which other applications have registered with the driver.
- *
- * See the note above regarding the ugly type-cast.
- * See the note above regarding VM.
- **********************************End Comment************************************/
- OSErr
- TDriver::iacStatus(ParmBlkPtr sParmBlock)
- {
- #ifdef DEBUG
- DebugStr("\pIn Status now.");
- #endif
- switch (sParmBlock->cntrlParam.csCode)
- {
- case kAnyMsgForMe :
- this->AnyMessagesForMe( ((IACRecord *) *((long *) &(sParmBlock->cntrlParam.csParam)) ));
- return (sParmBlock->cntrlParam.ioResult = kNoErr);
- case kWhosThere :
- this->WhosThere( ((IACRecord *) *((long *) &(sParmBlock->cntrlParam.csParam)) )) ;
- return (sParmBlock->cntrlParam.ioResult = kNoErr);
- default :
- return (kBadCsCode);
- }; // switch statement
- return(kNoErr); // The linker warns about "no return values" if I don't put this in.
- } // TDriver::iacStatus
-
-
- /**********************************Comment*****************************************
- * TDriver::iacClose dispose of all the messages allocated, and unregister any
- * application names.
- **********************************End Comment************************************/
- OSErr
- TDriver::iacClose(ParmBlkPtr cParmBlock)
- {
- short i;
- char zeroChar = kZeroChar;
- TMessPtr aMsgPtr;
-
- #ifdef DEBUG
- DebugStr("\pIn Close now.");
- #endif
-
- for(i = 0; i < kMaxApps; i++)
- {
- if((this->GetAppName(i))[0] != kZeroChar)
- this->SetAppName(i,&zeroChar);
- }
- for(i = 0; i < kMaxMessages; i++)
- {
- if((aMsgPtr = this->GetMessage(i)))
- {
- DisposPtr((Ptr) aMsgPtr);
- this->SetMessage(i,nil);
- }
- }
- return (cParmBlock->ioParam.ioResult = noErr);
- }
-
-
- // Private routines
-
- /**********************************Comment*****************************************
- * TDriver::SetAppName is a standard Set routine. It's the only place you'll find the
- * data member modified. Thus, in the future, if I want to do something with how
- * the appname is stored, all I have to do is modify this routine.
- * I wanted the appname to be stored in the driver's storage, so we use the string
- * copy routine.
- **********************************End Comment************************************/
- void
- TDriver::SetAppName(short signature,char *anAppName)
- {
- tseStrCpy((char *) &(fAppNameArray[signature]),anAppName);
- } // TDriver::SetAppName
-
-
- /**********************************Comment*****************************************
- * TDriver::GetAppName is a standard Get routine. It's the only place you'll find the
- * data member returned. Thus, in the future, if I want to do something with how
- * the appname is returned, all I have to do is modify this routine.
- **********************************End Comment************************************/
- char*
- TDriver::GetAppName(short signature)
- {
- return (char *)&(fAppNameArray[signature]);
- }
-
- /**********************************Comment*****************************************
- * TDriver::SetMessage is a standard Set routine. It's the only place you'll find the
- * data member modified. Thus, in the future, if I want to do something with how
- * the TMessage pointer is stored, all I have to do is modify this routine.
- **********************************End Comment************************************/
- void
- TDriver::SetMessage(short index, TMessPtr aMsgPtr)
- {
- fMessageArray[index] = aMsgPtr;
- } // TDriver::SetMessage
-
-
- /**********************************Comment*****************************************
- * TDriver::GetMessage is a standard Get routine. It's the only place you'll find the
- * data member returned. Thus, in the future, if I want to do something with how
- * the message is returned, all I have to do is modify this routine. As it is now,
- * a pointer to a TMessage object is returned.
- **********************************End Comment************************************/
- TMessPtr
- TDriver::GetMessage(short index)
- {
- return (fMessageArray[index]);
- } // TDriver::GetMessage
-
-
- /**********************************Comment*****************************************
- * TDriver::AnyMessagesForMe returns TRUE if there are any messages which are being
- * sent to the app whose signature is anIACPtr->mySignature. The routine will loop
- * through all the messages using GetMessage, and it'll as the MESSAGE if the message
- * is bound for the app whose signature is mySignature. It will return the index of
- * where the message is in actualCount. So, the caller can test for actualCount > 0
- * to see if there were any messages. Otherwise, if there are no messages, actualCount
- * is set to kNoMore.
- **********************************End Comment************************************/
- Boolean
- TDriver::AnyMessagesForMe(IACRecord *anIACPtr)
- {
- TMessPtr aMsgPtr;
- short i;
-
- anIACPtr->partnerSig = 0;
- anIACPtr->actualCount = kNoMore;
-
- for (i = 0; i < kMaxMessages; i++)
- {
- if((aMsgPtr = GetMessage(i)) != nil)
- {
- if(aMsgPtr->IsMessageForMe(anIACPtr->mySignature))
- anIACPtr->actualCount = i;
- } // if message is not nil
- } // for loop
-
- return (anIACPtr->actualCount != kNoMore);
- } // TDriver::AnyMessagesForMe
-
-
- /**********************************Comment*****************************************
- * TDriver::WhosThere returns, in the appName parameter the name of the
- * application whose signature is indexForWhosThere. For a calling application to
- * find all registered apps, they'd start with indexForWhosThere at zero and loop
- * through until it returned zero in actualCount. If there's only one application
- * registered, it's the one who's doing the calling.
- * The procedure stops once it has found just two applications registered. It
- * increments the indexForWhosThere so the next time through, it'll return the next
- * application name in appName. It returns the signature of the "partner" in
- * partnerSig so the calling application can send messages.
- **********************************End Comment************************************/
- void
- TDriver::WhosThere(IACRecord *anIACPtr)
- {
- short foundOne = 0, foundTwo = 0;
-
- anIACPtr->actualCount = nil;
- anIACPtr->partnerSig = nil;
-
- while ((anIACPtr->indexForWhosThere < kMaxApps) && (!foundTwo))
- {
- if((this->GetAppName(anIACPtr->indexForWhosThere))[0] != kZeroChar)
- {
- if(foundOne)
- {
- foundTwo = anIACPtr->indexForWhosThere;
- anIACPtr->actualCount = kMoreMessages;
- }
- else
- {
- foundOne = anIACPtr->indexForWhosThere;
- tseStrCpy(anIACPtr->appName,this->GetAppName(anIACPtr->indexForWhosThere));
- anIACPtr->partnerSig = foundOne;
- }
- }
- anIACPtr->indexForWhosThere++;
- } // while
- } // TDriver::WhosThere
-
-
-
- /**********************************Comment*****************************************
- * TDriver::UnregisterApp receives all the messages for the particular application
- * which is unregistering. Those messages will just get thrown away. So, all the
- * messages destined for it are disposed of, and then it sets the name to '\0' so
- * others can play.
- **********************************End Comment************************************/
- short
- TDriver::UnregisterApp(IACRecord *anIACPtr)
- {
- char zeroChar = kZeroChar;
-
- while (this->ReceiveMessage(anIACPtr) == kYesMessagesForMe) // gotta delete those suckers.
- ;
- this->SetAppName(anIACPtr->mySignature,&zeroChar); // zero the name so others can play.
- return (kNoErr);
- } // TDriver::UnregisterApp
-
-
- /**********************************Comment*****************************************
- * TDriver::RegisterApp looks to see if there's an open "slot". If so, it sets the
- * new AppName for that "slot" and returns the "slot" as the signature. If it couldn't
- * find any open "slots" then it returns the kNoMore error.
- **********************************End Comment************************************/
- short
- TDriver::RegisterApp(IACRecord *anIACPtr)
- {
- short i = 0;
- short canDo = kNoMore;
-
- while ((i < kMaxApps) && (canDo == kNoMore))
- {
- if((this->GetAppName(i))[0] == kZeroChar)
- {
- canDo = kNoErr;
- anIACPtr->mySignature = i;
- this->SetAppName(i,anIACPtr->appName);
- }
- i++;
- }
- return (canDo);
- } // TDriver::RegisterApp
-
-
- /**********************************Comment*****************************************
- * TDriver::SendMessage has to instantiate a new message object. It also has to
- * remember that message for later when someone tries to receive it. To remember it,
- * the TDriver object places it in the message pointer array. If it couldn't find
- * an open "slot" in the array, it returns the error kMsgMemErr, meaning it has no
- * memory to store the pointer to the message and hence the message didn't get sent.
- * Since the TDriver object is creating a new TMessage, it will destroy the TMessage
- * when the time comes.
- **********************************End Comment************************************/
- short
- TDriver::SendMessage(IACRecord *anIACPtr)
- {
- TMessPtr aMsgPtr;
- short canDo = kNoMore;
- short i = 0;
-
- aMsgPtr = new TMessage(anIACPtr->messageString, anIACPtr->mySignature, anIACPtr->partnerSig);
- if(aMsgPtr)
- {
- while ((i < kMaxMessages) && (canDo == kNoMore))
- {
- if(this->GetMessage(i) == nil)
- {
- this->SetMessage(i, aMsgPtr);
- canDo = kNoErr;
- }
- i++;
- }
- if (canDo == kNoMore)
- delete aMsgPtr;
- } // if aMsgPtr
- else
- canDo = kMsgMemErr;
- return (canDo);
- } // TDriver::SendMessage
-
-
- /**********************************Comment*****************************************
- * TDriver::ReceiveMessage finds any messages for the application whose signature is
- * mySignature. It first checks to see if there are any messages. If so, it gets
- * the message, and asks the TMessage object to return the message string. Then, it
- * copies the message string to the calling applications message buffer, puts the
- * sender's signature in "partnerSig", and the sender's application name in appName.
- * It then sets the "slot" in the message array to nil, and disposes of the TMessage
- * object. If there were messages, it returns the kYesMessagesForMe value, otherwise
- * it returns kNoMore.
- **********************************End Comment************************************/
- short
- TDriver::ReceiveMessage(IACRecord *anIACPtr)
- {
- TMessPtr aMsgPtr;
- short sender;
- char *bufP = nil;
-
- if(this->AnyMessagesForMe(anIACPtr))
- {
- aMsgPtr = this->GetMessage(anIACPtr->actualCount);
- (void) aMsgPtr->IsMessageForMe(anIACPtr->mySignature,&sender,bufP);
- anIACPtr->partnerSig = sender;
- tseStrCpy(anIACPtr->messageString,bufP);
- tseStrCpy(anIACPtr->appName, this->GetAppName(anIACPtr->partnerSig));
- this->SetMessage(anIACPtr->actualCount,nil);
- delete aMsgPtr;
- return (kYesMessagesForMe);
- }
- else
- return(kNoMore);
- } // TDriver::ReceiveMessage
-